package cn.tedu.icop.basic.service.impl;
import cn.tedu.icop.basic.dao.repository.StationRepository;
import cn.tedu.icop.basic.pojo.StationPO;
import cn.tedu.icop.basic.pojo.StationVO;
import cn.tedu.icop.basic.service.StationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.BoundGeoOperations;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Slf4j
@Service
public class StationServiceImpl implements StationService {
    public static final String KEY_STATION_GEO = "stations_geo";
    private static final Object KEY_STATIONS_DETAIL = "stations_detail";
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StationRepository stationRepository;

    /**
     * 我的位置(点) 经纬度 按照 范围(1公里,10公里)为半径画一个圆,
     * 落在圆形里所有的 充电站位置(经纬度),并且按照距离排序
     * @param longitude
     * @param latitude
     * @param radius
     * @return
     */
    @Override
    public List<StationVO> getNearStationList(Double longitude, Double latitude, Double radius) {
        //1.基于用户位置绘制一个圆
        //1.1,创建用户的位置对象 point (圆心)
        Point userPosition = new Point(longitude, latitude);
        //1.2,创建查找范围距离distance (半径)
        Distance distance = new Distance(radius, Metrics.KILOMETERS);
        //1.3,基于圆心和半径创建圆对象circle
        Circle circle = new Circle(userPosition, distance);

        //2,构建查询附近站的参数
        RedisGeoCommands.GeoRadiusCommandArgs args =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        //2.1 设置redis返回距离
        args.includeDistance();
        //2.2 设置redis返回坐标
        args.includeCoordinates();

        //3,查找附近充电站
        //3.1获取redis中存储的预加载的站点信息
        BoundGeoOperations boundGeoOperations =
                redisTemplate.boundGeoOps(KEY_STATION_GEO);
        //3.2 从redis存储的站点中查询距离当前位置指定距离(附近)的充电站
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults =
                boundGeoOperations.radius(circle, args);
        //4.基于找到的附近站点信息，获取站点详情，然后存储list集合返回给用户。
        //4.1,获取redis中存储的所有站详情信息
        BoundHashOperations boundHashOperations =
                redisTemplate.boundHashOps(KEY_STATIONS_DETAIL);
        //4.2,获取所有站信息对应的迭代器对象。
        Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator =
                geoResults.iterator();
        //4.2 遍历迭代器中的栈信息，并将其存储到list集合，返回给调用者
        ArrayList<StationVO> arrayList = new ArrayList<>();
        while (iterator.hasNext()) {
            //4.2.1获取一个场站站点信息
            GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult =
                    iterator.next();
            //4.2.1 获取场站的id
            String id =geoResult.getContent().getName();//field
            //4.2.2 根据id从stationDetailHash得到充电站详情
            StationPO staticPO = (StationPO) boundHashOperations.get(id);
            //4.2.3 得到距离
            double stationDistance = geoResult.getDistance().getValue();
            //4.2.4 创建vo
            StationVO stationVO = new StationVO();
            BeanUtils.copyProperties(staticPO,stationVO);
            stationVO.setDistance(stationDistance);
            //4.2.5 把vo放到集合
            arrayList.add(stationVO);
        }
        log.debug("arrayList:{}",arrayList);
        return arrayList;
    }
    @Override
    public StationVO getStation(Integer gunId) {
        BoundHashOperations stationsDetail =
                redisTemplate.boundHashOps("stations_detail");
        StationPO stationPO=(StationPO)stationsDetail.get(String.valueOf(gunId));
        if (stationPO==null){
            stationPO=stationRepository.selectStationById(gunId);
        }
        StationVO stationVO=new StationVO();
        BeanUtils.copyProperties(stationPO,stationVO);
        return stationVO;
    }

}